/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.explorer.view;
import java.util.TooManyListenersException;
import java.awt.dnd.*;
import java.awt.Point;
import java.awt.Cursor;
import java.awt.datatransfer.Transferable;
import java.io.IOException;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import javax.swing.JTree;
import javax.swing.tree.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import org.openide.nodes.Node;
import org.openide.TopManager;
import org.openide.util.datatransfer.ExClipboard;
/** Support for the drag operations in the TreeView.
*
* @author Dafe Simonek
*/
final class TreeViewDragSupport implements DragSourceListener,
DragGestureListener,
TreeSelectionListener {
// Attributes
/** True when we are active, false otherwise */
boolean active = false;
/** Recognizes default gesture */
DragGestureRecognizer defaultGesture;
/** Holds content of the selection in tree.
* It's here only for workaround of sun's bug */
TreePath[] curSelection;
TreePath[] oldSelection;
// Associations
/** The view that manages viewing the data in a tree. */
protected TreeView view;
/** The tree which we are supporting (our client) */
protected JTree tree;
/** Cell renderer - PENDING - do we need it? */
//protected DnDTreeViewCellRenderer cellRenderer;
// Operations
/** Creates new TreeViewDragSupport, initializes gesture */
public TreeViewDragSupport (TreeView view, JTree tree) {
this.view = view;
this.tree = tree;
// it's here only because of workaround for sun's bug
tree.addTreeSelectionListener(this);
}
/** Initiating the drag */
public void dragGestureRecognized (DragGestureEvent dge) {
int dragAction = dge.getDragAction();
// check allowed actions
if ((dragAction & view.getAllowedDragActions()) == 0)
return;
// obtain the nodes to work with
Node[] nodes = obtainNodes(dge);
// check nodes
if (nodes == null)
return;
// check if the nodes are willing to do selected action
for (int i = 0; i < nodes.length; i++) {
if (!DragDropUtilities.checkNodeForAction(nodes[i], dragAction))
return;
}
// get transferable and start the drag
try {
Transferable transferable =
DragDropUtilities.getNodeTransferable(nodes, dragAction);
//System.out.println("Transferable: " + transferable); // NOI18N
dge.startDrag(
DragDropUtilities.chooseCursor(dragAction, view.isDropTarget()),
transferable,
this
);
// notify tree cell editor that DnD operationm is active
TreeCellEditor tce = tree.getCellEditor();
if (tce instanceof TreeViewCellEditor)
((TreeViewCellEditor)tce).setDnDActive(true);
} catch (InvalidDnDOperationException exc) {
// cannot start the drag, notify user
TopManager.getDefault().notifyException(exc);
} catch (IOException exc) {
// cannot start the drag, notify user
TopManager.getDefault().notifyException(exc);
}
}
public void dragEnter (DragSourceDragEvent dsde) {
}
public void dragOver (DragSourceDragEvent dsde) {
}
public void dropActionChanged (DragSourceDragEvent dsde) {
}
public void dragExit (DragSourceEvent dse) {
}
public void dragDropEnd (DragSourceDropEvent dsde) {
//System.out.println("DnD ended..."); // NOI18N
// notify tree cell editor that DnD operationm is active
// no more
TreeCellEditor tce = tree.getCellEditor();
if (tce instanceof TreeViewCellEditor)
((TreeViewCellEditor)tce).setDnDActive(false);
}
/** Activates or deactivates Drag support on asociated JTree
* component
* @param active true if the support should be active, false
* otherwise
*/
public void activate (boolean active) {
if (this.active == active)
return;
this.active = active;
DragGestureRecognizer dgr = getDefaultGestureRecognizer();
if (active) {
dgr.setSourceActions(view.getAllowedDragActions());
try {
dgr.removeDragGestureListener(this);
dgr.addDragGestureListener(this);
} catch (TooManyListenersException exc) {
throw new InternalError("Too many listeners for drag gesture."); // NOI18N
}
} else {
dgr.removeDragGestureListener(this);
}
}
/** Safe getter for default gesture<br>
* (creates the gesture when called for the first time)
*/
DragGestureRecognizer getDefaultGestureRecognizer () {
if (defaultGesture == null) {
DragSource ds = DragSource.getDefaultDragSource();
defaultGesture = ds.createDefaultDragGestureRecognizer(
tree, view.getAllowedDragActions(), this);
}
return defaultGesture;
}
/** Utility method. Returns either selected nodes in tree
* (if cursor hotspot is above some selected node) or the node
* the cursor points to.
* @return Node array or null if position of the cursor points
* to no node.
*/
Node[] obtainNodes (DragGestureEvent dge) {
Point dragOrigin = dge.getDragOrigin();
TreePath tp = tree.getPathForLocation(dragOrigin.x, dragOrigin.y);
Object obj = null;
// return if conditions are not satisfied
if ((tp == null) ||
!((obj = tp.getLastPathComponent()) instanceof Node))
return null;
// workaround for Sun's bug #4165577
// we must repair the selection before dragging
if ((oldSelection != null) && wasSelected(obj)) {
//System.out.println("Repairing..."); // NOI18N
tree.setSelectionPaths(oldSelection);
curSelection = null;
}
// ---end of workaround
Node[] result = null;
if (tree.isPathSelected(tp)) {
// cursor above selected, so return all selected nodes
TreePath[] tps = tree.getSelectionPaths();
result = new Node[tps.length];
Object curObj = null;
for (int i = 0; i < tps.length; i++) {
curObj = tps[i].getLastPathComponent();
if (!(curObj instanceof Node))
return null;
result[i] = (Node)curObj;
}
} else {
// return only the node the cursor is above
result = new Node[] { (Node)obj };
}
return result;
}
/** Stores last two selections.
* Workaround for sun's bug */
public void valueChanged (TreeSelectionEvent tse) {
TreePath[] newSelection = tree.getSelectionPaths();
if ((newSelection != null) &&
(!Arrays.equals(curSelection, newSelection))) {
oldSelection = (curSelection == null) ? newSelection : curSelection;
curSelection = newSelection;
}
}
/** @return True if given object was selected in old selection,
* false otherwise */
boolean wasSelected (Object obj) {
if (oldSelection == null)
return false;
for (int i = 0; i < oldSelection.length; i++) {
if (obj.equals(oldSelection[i].getLastPathComponent()))
return true;
}
return false;
}
} /* end class TreeViewDragSupport */
/*
* Log
* 9 Gandalf 1.8 1/13/00 Ian Formanek NOI18N
* 8 Gandalf 1.7 1/12/00 Ian Formanek NOI18N
* 7 Gandalf 1.6 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 6 Gandalf 1.5 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 5 Gandalf 1.4 5/17/99 David Simonek comments removed
* 4 Gandalf 1.3 4/30/99 David Simonek
* 3 Gandalf 1.2 4/28/99 David Simonek drag and drop in tree now
* supports multi-selection
* 2 Gandalf 1.1 4/27/99 David Simonek autoscroll support and
* visual feedback in DnD operations added
* 1 Gandalf 1.0 4/21/99 David Simonek
* $
*/